import os
import sys
import errno
import fuse
import math

from Verbosity import Verbosity

class WhateverFuse(fuse.Fuse):
	"""Gives FUSE functionality to the object. For further information about
	each method take a look on the FUSE-docs."""

	def __init__(self, *args, **kw):
		"""Constructor, creates the FUSE-instance."""
		fuse.Fuse.__init__(self, *args, **kw)

		self.verbosity=Verbosity(False, "* WhateverFuse,")

		self.dataStorage=None
	# End def
	
	def getDeEncodedPath(self, path):
		"""Decodes every coded parts of the given part.

		Example:
			/a/b/c -> a will be decoded, b too, and c also

		Parameter:
			string path Path string, which should be decoded.

		Return:
			string Decoded path-string.
		"""

		parts=path.split(os.sep)
		for k in range(0, len(parts)):
			parts[k]=parts[k].decode(sys.stdin.encoding)
		# End for
		path="%s%s" % (os.sep, os.sep.join(parts[1:]))

		return path
	# End def

	def getattr(self, path):
		"""Returns a stat-structure."""

		self.verbosity.out("getattr: path: %s" % path)

		path=self.getDeEncodedPath(path)

		st=self.dataStorage.getStatStruct(path)

		return st if st else -errno.ENOENT
	# End def

	def readdir(self, path, offset):
		"""Yields the directory-entries."""
		self.verbosity.out("readdir: path: %s, offset: %i" %(path, offset))

		path=self.getDeEncodedPath(path)

		if path==os.sep or self.dataStorage.hasPath(path):
			dirEntries=[os.curdir, os.pardir]+self.dataStorage.getPathEntries(path)
			
			for dirEntry in dirEntries[offset:]:
				s=dirEntry
				if type(s)==unicode:
					s=s.encode(sys.stdout.encoding)
				else:
					s=str(s)
				# End if

				yield fuse.Direntry(s)
			# End for
		# End if
	# End def

	def mythread (self):
		"""mythread, not yet implemented."""
		self.verbosity.out("mythread")

		return -errno.ENOSYS
	#  End def

	def chmod ( self, path, mode ):
		"""chmod, not yet implemented."""
		self.verbosity.out("chmod: path: %s, mode: %i" % (path, mode))

		return -errno.ENOSYS
	# End def

	def chown ( self, path, uid, gid ):
		"""chown, not yet implemented."""
		self.verbosity.out("chmod: path: %s, uid: %i, gid: %i" % (path, uid, gid))

		return -errno.ENOSYS
	# End def

	def fsync ( self, path, isFsyncFile ):
		"""fsync, not yet implemented."""
		self.verbosity.out("fsync: path: %s, isFsyncFile: %s" % (path, isFsyncFile))

		return -errno.ENOSYS
	# End def

	def link ( self, targetPath, linkPath ):
		"""link, not yet implemented."""
		self.verbosity.out("link: targetPath: %s, linkPath: %s" % (targetPath, linkPath))

		return -errno.ENOSYS
	# End def

	def mkdir( self, path, mode ):
		"""Creates a directory.

		Parameter:
			string path The directory-path which should be created.
			integer mode The filesystem-mode which should be set, NOT IMPLEMENTED.
		"""

		self.verbosity.out("mkdir: path: %s, mode: %i" % (path, mode))

		path=self.getDeEncodedPath(path)

		try:
			self.dataStorage.setData(path, {})
			return 0
		except:
			return -errno.ENOSYS
		# End try/except
	#  End def

	def rmdir( self, path ):
		"""Removes/Deletes a directory.

		Parameter:
			string path The directory-path which should be removed/deleted.
		"""

		self.verbosity.out("rmdir: path: %s" % path)

		path=self.getDeEncodedPath(path)

		if len(self.dataStorage.getData(path))==0:
			self.dataStorage.delData(path)
			return 0
		else:
			return -errno.ENOTEMPTY
		# End if
	# End def

	def mknod(self, path, mode, rdev):
		"""Creates a "file", in JSON that means not an object, array or something like this.

		Parameter:
			string path The path-string-named file which should be created.
			integer mode Type of file and permissions, NOT IMPLEMENTED.
			integer rdev Contains a device-id, NOT IMPLEMENTED.
		"""

		self.verbosity.out("mknod: path: %s, mode: %i, rdev: %i" % (path, mode, rdev))

		path=self.getDeEncodedPath(path)

		try:
			self.dataStorage.setData(path, "")
			return 0
		except:
			return -errno.ENOSYS
		# End try/except
	# End def

	def readlink( self, path ):
		"""readlink, not yet implemented."""
		self.verbosity.out("readlink: path: %s" % path)

		return -errno.ENOSYS
	# End def

	def rename(self, oldPath, newPath):
		"""Renames/Moves an current/old path to a new name/location.

		Parameter:
			string oldPath Path-String which should be renamed/moved.
			string newPath Path-String where the oldPath should be renamed/moved to.
		"""

		self.verbosity.out("rename: oldPath: %s, newPath: %s" % (oldPath, newPath))

		oldPath=self.getDeEncodedPath(oldPath)
		newPath=self.getDeEncodedPath(newPath)

		try:
			self.dataStorage.setData(newPath, self.dataStorage.getData(oldPath))
			self.dataStorage.detData(oldPath)
			return 0
		except:
			return -errno.ENOSYS
		# End try/except
	# End def

	def statfs(self):
		"""Returns information about the imaginary filesystem, like block-sizes, available spaces, aso."""

		statvfs=os.statvfs(".")
		rvfs=fuse.StatVfs(f_bsize=statvfs.f_bsize, f_frsize=statvfs.f_bsize, f_blocks=statvfs.f_blocks, f_bfree=0, f_bavail=0, f_files=statvfs.f_files, f_ffree=statvfs.f_ffree, f_namemax=statvfs.f_namemax)

		# Actually filesize
		blockSize=long(math.ceil(self.dataStorage.getSizeOf("/"))/(statvfs.f_bsize*1.0))
		rvfs.f_blocks=blockSize if blockSize else 1

		self.verbosity.out("statfs: %s" % str(rvfs))

		return rvfs
	# End def

	def symlink( self, targetPath, linkPath ):
		"""symlink, not yet implemented."""

		self.verbosity.out("symlink: targetPath: %s, linkPath: %s" % (targetPath, linkPath))

		return -errno.ENOSYS
	# End def

	def truncate(self, path, size):
		"""Truncates the given path-string(file).

		Parameter:
			string path Path-String which shold be truncated.
			integer size Size-position to which should be truncated.
		"""
		
		self.verbosity.out("truncate: path: %s, size: %i" % (path, size))

		path=self.getDeEncodedPath(path)

		try:
			self.dataStorage.setData(path, str(self.dataStorage.getData(path))[:size])
			return 0
		except:
			return -errno.ENOSYS
		# End try/except
	# End def

	def unlink(self, path):
		"""Removes/deletes a file.
		
		Parameter:
			string path Path-String which should be removed/deleted.
		"""

		self.verbosity.out("unlink: path: %s" % path)

		path=self.getDeEncodedPath(path)

		try:
			self.dataStorage.delData(path)
			return 0
		except:
			return -errno.ENOSYS
		# End try/except
	# End def

	def utime(self, path, times):
		"""Sets the times of the json-dir world-data. Every directory/file has the
		same times, atime, mtime, ctime, because json-data is under the score one file.
		
		Parameter:
			string path Path-String of which the times should be set.
			tuple times A tuple of times, simply the first one will be used.
		"""

		return 0
	# End def

	def read(self, path, size, offset):
		"""Reads/Returns size-bytes from the beginning of the offset-position of the given file.

		Parameter:
			string path Path-String which should be read/returned.
			integer size Size of bytes which should be read/returned.
			integer offset Offset-position from which should be read/returned size bytes.
		"""
		self.verbosity.out("read: path: %s, size: %i, offset: %i" % (path, size, offset))

		path=self.getDeEncodedPath(path)

		try:
			r=self.dataStorage.getData(path)
			return r[offset:offset+size]
		except:
			return -errno.EIO
		#  End try/except
	# End def

	def open( self, path, flags ):
		"""Opens the internal file-handler.

		Parameter:
			string path Path-String which should be opened.
			integer flags Combination of file-structures-flags, NOT IMPLEMENTED.
		"""
		self.verbosity.out("open: path: %s, flags: %i" % (path, flags))

		path=self.getDeEncodedPath(path)

		try:
			self.dataStorage.setData(path, self.dataStorage.getData(path).encode(self.dataStorage.getEncoding()))
		except:
			pass
		# End try/except

		return 0
	# End def

	def write(self, path, buf, offset):
		"""Writes buf-data to the offset-position of the path-file.

		Parameter:
			string path Path-String to which should be written.
			bytes buf Raw-data which should be written to the offset-position.
			integer offset Offset-position to which should be written.
		"""

		self.verbosity.out("write: path: %s, buf: %s, offset: %i" % (path, "...", offset))

		path=self.getDeEncodedPath(path)

		try:
			# Assign newly given buf-data
			tmpDataStorage=self.dataStorage.getData(path)
			self.dataStorage.setData(path, tmpDataStorage[0:offset]+buf+tmpDataStorage[offset+len(buf):])

			# Return written length
			return len(buf)
		except:
			return -errno.ENOSYS
		# End try/except
	#  End def

	def release(self, path, flags):
		"""Closes the internal file-handler.

		Transforms the data behind the path. Take a look on "Translate Boolean/
		Numbers/None".

		Parameter:
			string path Path-String which should be closed.
			integer flags Combination of file-structures-flags, NOT IMPLEMENTED.
		"""

		self.verbosity.out("release: path: %s, flags: %i" % (path, flags))

		path=self.getDeEncodedPath(path)

		try:
			self.dataStorage.setData(path, self.dataStorage.getData(path).decode(self.dataStorage.getEncoding()))
		except:
			pass
		# End try/except

		return 0
	# End def

# End class
